package com.shadow.demo.data.redis;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.management.RuntimeErrorException;
import java.util.concurrent.TimeUnit;

/**
 * Redis hash 的基本操作.
 */
@Slf4j
@Service
public class RedisService {


    /** 当前系统标识，作为缓存前缀. **/
    @Value("${app.name}")
    private String appName;

    /** redis操作模板. **/
    private final RedisTemplate<String, Object> redisTemplate;

    RedisService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 获取当前系统redis标识前缀.
     * @param  key hash表
     * @return  String
     **/
    private String getSysKey(final String key) {
        return "zoneland_" + this.appName + "_" + key;
    }

    /**
     * 向Hash中添加值.
     * @param key      可以对应数据库中的表名
     * @param field    可以对应数据库表中的唯一索引
     * @param value    存入redis中的值
     * @param expireHours    失效小时数
     */
    public void hset(final String key, final String field, final String value, final long expireHours) {
        try {
            if (StringUtils.isNotBlank(key)) {
                redisTemplate.opsForHash().put(getSysKey(key), field, value);
                if (0L != expireHours) {
                    redisTemplate.expire(getSysKey(key), expireHours, TimeUnit.HOURS);
                }
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hset {}的{}缓存设置失败", getSysKey(key), field, e);
        }
    }

    /**
     * 从redis中取出值.
     * @param key 可以对应数据库中的表名
     * @param field 可以对应数据库表中的唯一索引
     * @return String
     */
    public String hget(final String key, final String field) {
        String result = null;
        try {
            if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(field)) {
                result = (String) redisTemplate.opsForHash().get(getSysKey(key), field);
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hget {}的{}缓存是否存在失败", getSysKey(key), field, e);
        }
        return result;
    }

    /**
     * 判断 是否存在 key 以及 hash key.
     * @param key 可以对应数据库中的表名
     * @param field 可以对应数据库表中的唯一索引
     * @return boolean
     */
    public boolean hexists(final String key, final String field) {
        boolean exist = false;
        try {
            if (StringUtils.isNotBlank(key)) {
                exist = redisTemplate.opsForHash().hasKey(getSysKey(key), field);
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hexists {}的{}缓存是否存在失败", getSysKey(key), field, e);
        }
        return exist;
    }

    /**
     * 查询 key中对应多少条数据.
     * @param key 可以对应数据库中的表名
     * @return long
     */
    public long hsize(final String key) {
        long size = 0L;
        try {
            if (StringUtils.isNotBlank(key)) {
                size = redisTemplate.opsForHash().size(getSysKey(key));
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hsize 获取{}缓存长度失败", getSysKey(key), e);
        }
        return size;
    }

    /**
     * 删除表.
     * @param key 可以对应数据库中的表名
     */
    public void hdel(final String key) {
        try {
            if (StringUtils.isNotBlank(key)) {
                redisTemplate.delete(getSysKey(key));
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hdel {}缓存删除失败", getSysKey(key), e);
        }
    }

    /**
     * 删除项.
     * @param key 可以对应数据库中的表名
     * @param field 可以对应数据库表中的唯一索引
     */
    public void hdel(final String key, final String field) {
        try {
            if (StringUtils.isNotBlank(key)) {
                redisTemplate.opsForHash().delete(getSysKey(key), field);
            }
        } catch (RedisConnectionFailureException | RuntimeErrorException e) {
            log.error("hdel {}的{}缓存删除失败", getSysKey(key), field, e);
        }
    }
}
